package com.zrkizzy.module.system.service.dict;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zrkizzy.common.core.utils.IdUtil;
import com.zrkizzy.common.core.utils.StringUtil;
import com.zrkizzy.common.core.utils.bean.BeanCopyUtil;
import com.zrkizzy.common.models.domain.system.dict.DictData;
import com.zrkizzy.common.models.dto.system.dict.DictDataDTO;
import com.zrkizzy.common.models.query.system.dict.DictDataQuery;
import com.zrkizzy.common.models.vo.system.dict.DictDataOptionVO;
import com.zrkizzy.common.redis.enums.RedisKey;
import com.zrkizzy.common.redis.service.IRedisService;
import com.zrkizzy.module.system.exception.DictErrorCode;
import com.zrkizzy.module.system.mapper.dict.DictDataMapper;
import com.zrkizzy.system.facade.service.dict.IDictDataService;
import com.zrkizzy.system.facade.service.dict.IDictTypeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 字典数据业务逻辑接口实现类
 * </p>
 *
 * @author zhangrongkang
 * @since 2024/1/18
 */
@Service
@Slf4j
public class DictDataServiceImpl implements IDictDataService {

    @Autowired
    private IdUtil idUtil;

    @Autowired
    private IRedisService redisService;

    @Autowired
    private IDictTypeService dictTypeService;

    @Autowired
    private DictDataMapper dictDataMapper;

    /**
     * 获取所有字典数据
     *
     * @param dictDataQuery 字典数据查询对象
     * @return 字典数据分页数据
     */
    @Override
    public Page<DictData> listDictData(DictDataQuery dictDataQuery) {
        // 开启分页
        Page<DictData> page = new Page<>(dictDataQuery.getCurrentPage(), dictDataQuery.getPageSize());
        QueryWrapper<DictData> queryWrapper = getDictDataQueryWrapper(dictDataQuery);
        // 查询分页
        return dictDataMapper.selectPage(page, queryWrapper);
    }

    /**
     * 定义字典数据查询条件
     *
     * @param dictDataQuery 字典数据查询对象
     * @return 查询条件
     */
    private QueryWrapper<DictData> getDictDataQueryWrapper(DictDataQuery dictDataQuery) {
        // 定义查询条件
        QueryWrapper<DictData> queryWrapper = new QueryWrapper<>();
        // 获取时间范围
        List<String> dataRange = dictDataQuery.getDataRange();
        // 如果时间范围不为空
        if (!CollectionUtils.isEmpty(dataRange)) {
            // 拼接时间范围查询条件
            queryWrapper.between("create_time", dataRange.get(0), dataRange.get(1));
        }
        if (Objects.nonNull(dictDataQuery.getStatus())) {
            // 状态（1 正常 0 停用）
            queryWrapper.eq("status", dictDataQuery.getStatus());
        }
        // 字典标签
        if (StringUtil.isNoneBlank(dictDataQuery.getDictLabel())) {
            queryWrapper.like("dict_label", dictDataQuery.getDictLabel());
        }
        // 字典类型一定不为空
        queryWrapper.eq("dict_type_id", dictDataQuery.getDictTypeId());
        // 返回内容根据排序字段进行排序
        queryWrapper.orderByAsc("sort");
        return queryWrapper;
    }

    /**
     * 添加或更新字典数据
     *
     * @param dictDataDTO 字典数据数据接收对象
     * @return 是否添加/更新成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveDictData(DictDataDTO dictDataDTO) {
        // 删除Redis对应数据
        dictTypeService.deleteCacheById(dictDataDTO.getDictTypeId());
        // 根据是否包含ID来判断添加-更新操作
        return Objects.nonNull(dictDataDTO.getId()) ? updateDictData(dictDataDTO) : insertDictData(dictDataDTO);
    }

    /**
     * 获取指定字典数据信息
     *
     * @param dictDataId 字典数据ID
     * @return 字典数据数据返回对象
     */
    @Override
    public DictData getDictDataById(Long dictDataId) {
        return dictDataMapper.selectById(dictDataId);
    }
    
    /**
     * 批量删除字典数据
     *
     * @param ids 字典数据ID
     * @return true：删除成功，false：删除失败
     */
    @Override
    public Boolean deleteBatch(List<Long> ids) {
        // 要删除的字典数据一定义同一类型下的字典数据，因此只需要取一个字典获取到字典类型ID
        if (!CollectionUtils.isEmpty(ids)) {
            // 清除缓存
            Long dictTypeId = dictDataMapper.getDictTypeIdById(ids.getFirst());
            dictTypeService.deleteCacheById(dictTypeId);
        }

        return dictDataMapper.deleteBatchIds(ids) == ids.size();
    }

    /**
     * 获取字典类型对应数据
     *
     * @param dictType 字典类型
     * @return 字典数据选项
     */
    @Override
    public List<DictDataOptionVO> listDictDataByType(String dictType) {
        String redisKey = RedisKey.DICT_KEY.getKey() + dictType;
        // 查询缓存中的字典数据
        List<DictDataOptionVO> list = redisService.getList(redisKey, DictDataOptionVO.class);
        if (!CollectionUtils.isEmpty(list)) {
            return list;
        }
        // 根据字典类型获取对应字典类型ID
        Long dictTypeId = dictTypeService.getDictTypeIdByType(dictType);
        if (Objects.isNull(dictTypeId)) {
            // 抛出已经被禁用异常
            throw DictErrorCode.DICT_TYPE_ALREADY_DISABLE.exception(dictType);
        }
        // 数据库中查询字典数据并存储到Redis
        QueryWrapper<DictData> queryWrapper = new QueryWrapper<DictData>().eq("dict_type_id", dictTypeId).eq("status", true).orderByAsc("sort");
        List<DictDataOptionVO> result = BeanCopyUtil.copyList(dictDataMapper.selectList(queryWrapper), DictDataOptionVO.class);
        redisService.setList(redisKey, result);
        return result;
    }

    /**
     * 更新当前字典数据
     *
     * @param dictDataDTO 字典数据数据接收对象
     * @return 是否更新成功
     */
    private Boolean updateDictData(DictDataDTO dictDataDTO) {
        // 对字典数据进行更新操作并返回响应结果
        return dictDataMapper.updateById(BeanCopyUtil.copy(dictDataDTO, DictData.class)) == 1;
    }
    
    /**
     * 添加新的字典数据
     *
     * @param dictDataDTO 字典数据数据接收对象
     * @return 是否添加成功
     */
    private Boolean insertDictData(DictDataDTO dictDataDTO) {
        // 生成字典数据ID
        Long id = idUtil.nextId();
        // 设置ID
        dictDataDTO.setId(id);
        // 添加字典数据数据并返回添加结果
        return dictDataMapper.insert(BeanCopyUtil.copy(dictDataDTO, DictData.class)) == 1;
    }

}
